Android广播之注册广播(包括静态广播和动态广播的注册)源码分析

Android广播按发送方式分类有三种:无序广播、有序广播(OrderedBroadcast)和粘性广播(StickyBroadcast)。

静态广播的注册流程:

在系统服务启动时会添加PackageManagerService,在该类的构造方法中就会对各个应用安装目录的apk文件进行扫描解析。先看下时序图:

先看PackageManagerService类的构造方法:

// Keys are String (package name), values are Package.  This also serves
// as the lock for the global state.  Methods that must be called with
// this lock held have the prefix "LP".
@GuardedBy("mPackages")// 域注解:是对类里面成员变量加的注解.受与mPackages引用相关联的锁保护
final ArrayMap<String, PackageParser.Package> mPackages =
        new ArrayMap<String, PackageParser.Package>();

public PackageManagerService(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
    . . .
    // Collect ordinary system packages.
    final File systemAppDir = new File(Environment.getRootDirectory(),
            "app");
    scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
            | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
    // 扫描其他路径
    . . .
}

private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
    final File[] files = dir.listFiles();
    if (ArrayUtils.isEmpty(files)) {
        Log.d(TAG, "No files in app dir " + dir);
        return;
    }

    if (DEBUG_PACKAGE_SCANNING) {
        Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
                + " flags=0x" + Integer.toHexString(parseFlags));
    }

    Log.d(TAG, "start scanDirLI:"+dir);
    // use multi thread to speed up scanning
    int iMultitaskNum = SystemProperties.getInt("persist.pm.multitask", 6);
    Log.d(TAG, "max thread:" + iMultitaskNum);
    final MultiTaskDealer dealer = (iMultitaskNum > 1) ? MultiTaskDealer.startDealer(
            MultiTaskDealer.PACKAGEMANAGER_SCANER, iMultitaskNum) : null;

    for (File file : files) {
        final boolean isPackage = (isApkFile(file) || file.isDirectory())
                && !PackageInstallerService.isStageName(file.getName());
        if (!isPackage) {
            // Ignore entries which are not packages
            continue;
        }

        if (RegionalizationEnvironment.isSupported()) {
            if (RegionalizationEnvironment.isExcludedApp(file.getName())) {
                Slog.d(TAG, "Regionalization Excluded:" + file.getName());
                continue;
            }
        }

        final File ref_file = file;
        final int ref_parseFlags = parseFlags;
        final int ref_scanFlags = scanFlags;
        final long ref_currentTime = currentTime;
        Runnable scanTask = new Runnable() {
            public void run() {
                try {
                    // 扫描文件
                    scanPackageLI(ref_file, ref_parseFlags | PackageParser.PARSE_MUST_BE_APK,
                            ref_scanFlags, ref_currentTime, null);
                } catch (PackageManagerException e) {
                    Slog.w(TAG, "Failed to parse " + ref_file + ": " + e.getMessage());

                    // Delete invalid userdata apps
                    if ((ref_parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                            e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
                        logCriticalInfo(Log.WARN, "Deleting invalid package at " + ref_file);
                        if (ref_file.isDirectory()) {
                            mInstaller.rmPackageDir(ref_file.getAbsolutePath());
                        } else {
                            ref_file.delete();
                        }
                    }
                }
            }
        };

        if (dealer != null)
            dealer.addTask(scanTask);
        else
            scanTask.run();
    }

    if (dealer != null)
        dealer.waitAll();
    Log.d(TAG, "end scanDirLI:"+dir);
}

/*
 *  Scan a package and return the newly parsed package.
 *  Returns null in case of errors and the error code is stored in mLastScanError
 */
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
        long currentTime, UserHandle user) throws PackageManagerException {
    if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
    parseFlags |= mDefParseFlags;
    PackageParser pp = new PackageParser();
    pp.setSeparateProcesses(mSeparateProcesses);
    pp.setOnlyCoreApps(mOnlyCore);
    pp.setDisplayMetrics(mMetrics);

    if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
        parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
    }

    final PackageParser.Package pkg;
    try {
        // 根据文件路径解析文件
        pkg = pp.parsePackage(scanFile, parseFlags);
    } catch (PackageParserException e) {
        throw PackageManagerException.from(e);
    }
    . . .

    // Note that we invoke the following method only if we are about to unpack an application
    PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags
            | SCAN_UPDATE_SIGNATURE, currentTime, user);

    . . .
    return scannedPkg;
}


上面scanPackageLI方法中主要执行两个方法:PackageParser类中的parsePackage方法和PackageManagerService类中的scanPackageLI重载方法,这里按顺序看,先看parsePackage方法:

/** File name in an APK for the Android manifest. */
private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
/** Path prefix for apps on expanded storage */
private static final String MNT_EXPAND = "/mnt/expand/";
/**
 * Parse the package at the given location. Automatically detects if the
 * package is a monolithic style (single APK file) or cluster style
 * (directory of APKs).
 */
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
    if (packageFile.isDirectory()) {
        // 解析文件夹下所有apk文件
        return parseClusterPackage(packageFile, flags);
    } else {
        // 解析apk文件
        return parseMonolithicPackage(packageFile, flags);
    }
}

/**
 * Parse all APKs contained in the given directory, treating them as a
 * single package. This also performs sanity checking, such as requiring
 * identical package name and version codes, a single base APK, and unique
 * split names.
 */
private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
    // 解析文件夹下所有apk文件的基本信息
    final PackageLite lite = parseClusterPackageLite(packageDir, 0);

    if (mOnlyCoreApps && !lite.coreApp) {
        throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                "Not a coreApp: " + packageDir);
    }

    final AssetManager assets = new AssetManager(
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值